home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / du.arc / DUENTRY.C < prev    next >
C/C++ Source or Header  |  1990-10-05  |  7KB  |  272 lines

  1.  
  2. /* @(#) duentry.c 1.2 90/09/08 14:38:56 */
  3.  
  4. /*
  5.  * Package:    du - Enhanced "du" disk usage report generator.
  6.  * File:    duentry - Scan entries for disk usage.
  7.  *
  8.  * The "du_entry()" routine provides the disk usage of a filesystem entry.
  9.  * To process directories, the "du_dir()" routine will be run recursively.
  10.  *
  11.  * Sat Sep  8 14:34:56 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
  12.  *    Cleanup for distribution.
  13.  * Tue Apr 17 21:50:58 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
  14.  *    Original composition.
  15.  *
  16.  * Copyright 1990, Unicom Systems Development.  All rights reserved.
  17.  * See accompanying README file for terms of distribution and use.
  18.  */
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include "du.h"
  25.  
  26. #ifdef M_XENIX
  27. #   include <sys/ndir.h>
  28.     typedef struct direct DIRENT;
  29. #else
  30. #   include <dirent.h>
  31.     typedef struct dirent DIRENT;
  32. #endif
  33.  
  34. static char SccsID[] = "@(#) duentry.c 1.2 90/09/08 14:38:56";
  35.  
  36. /*
  37.  * Local procedures.
  38.  */
  39. BOOL du_dir();
  40.  
  41. /*
  42.  * External procedures.
  43.  */
  44. extern DIR *opendir();
  45. extern DIRENT *readdir();
  46. extern void exit();
  47.  
  48.  
  49. /*
  50.  * du_entry() - Initiate a disk usage report for a specified filesys entry.
  51.  */
  52. void du_entry(entry)
  53. char *entry;            /* name of the entry to check              */
  54. {
  55.     struct stat        sbuf;        /* for stat info on this entry          */
  56.     struct fsinfo    *fsinfop;    /* for filesys info on this entry     */
  57.     struct dskusage    tot_blocks;    /* to accumulate usage of this entry  */
  58.  
  59.     /*
  60.      * Get the information on this entry.
  61.      */
  62.     if ( stat(entry, &sbuf) != 0 ) {
  63.     errmssg(ERR_WARN,"couldn't stat '%s'", entry);
  64.     return;
  65.     }
  66.     if ( (fsinfop = fs_getinfo((struct fsinfo *)NULL, &sbuf)) == NULL ) {
  67.     errmssg(ERR_WARN,"couldn't get filesystem info for '%s'", entry);
  68.     return;
  69.     }
  70.  
  71.     switch ( sbuf.st_mode & S_IFMT ) {
  72.  
  73.     case S_IFREG:
  74.     set_usage(&tot_blocks, &sbuf, fs_numblocks(fsinfop, &sbuf));
  75.     if ( All_entries || Total_only )
  76.         print_usage(entry, &tot_blocks);
  77.     break;
  78.  
  79.     case S_IFDIR:
  80.     if ( chdir(entry) != 0 ) {
  81.         errmssg(ERR_WARN,"couldn't chdir to '%s'", entry);
  82.         break;
  83.     }
  84.     if ( du_dir(entry, &sbuf, fsinfop, &tot_blocks) && Total_only )
  85.         print_usage(entry, &tot_blocks);
  86.     if ( chdir(Curr_dir) != 0 )
  87.         errmssg(ERR_ABORT,"couldn't chdir back to '%s'", Curr_dir);
  88.     break;
  89.  
  90.     default:
  91.     if ( Print_errors ) {
  92.         fprintf(stderr, "%s: '%s' is not a file or directory\n",
  93.         Progname, entry);
  94.     }
  95.     return;
  96.  
  97.     }
  98.  
  99. }
  100.  
  101.  
  102. /*
  103.  * du_dir() - Scan through a specific directory and report its disk space
  104.  * usage.  No information is returned.  Depending upon certain options,
  105.  * this procedure might recursively scan encountered directories, or
  106.  * accumulate subdirectory usage in this directory.
  107.  */
  108. BOOL du_dir(dir_name, dir_statp, dir_fsinfop, dir_blocks_p)
  109. char        *dir_name;    /* pathname to the directory to scan          */
  110. struct stat    *dir_statp;    /* stat information on this directory          */
  111. struct fsinfo    *dir_fsinfop;    /* info on filesystem containing dir          */
  112. Reg struct dskusage *dir_blocks_p; /* storage for the usage              */
  113. {
  114.     Reg DIRENT        *dp;        /* current entry being checked          */
  115.     Reg char        *ent_basename;    /* ptr to basename portion of pathname*/
  116.     struct dskusage    ent_blocks;    /* usage statistics for current entry */
  117.     struct stat        ent_stat;    /* inode info for current entry          */
  118.     struct fsinfo    *ent_fsinfop;    /* info on filesys with current entry */
  119.     DIR            *dirp;        /* stream for dir being searched      */
  120.     char        ent_pathname[MAXNAMLEN]; /* full pathname of entry    */
  121.     long        nblocks;
  122.  
  123.     /*
  124.      * Setup a buffer to hold the full pathname of the entry being examined.
  125.      * We can just place a filename at "ent_basename" to make the full pathname.
  126.      */
  127.     ent_basename = strcpy(ent_pathname, dir_name) + strlen(dir_name);
  128.     *ent_basename++ = '/';
  129.  
  130.     /*
  131.      * Initialize the block count with the usage by the directory itself.
  132.      */
  133.     set_usage(dir_blocks_p, dir_statp, fs_numblocks(dir_fsinfop, dir_statp));
  134.  
  135.     /*
  136.      * Open up the directory so we can scan it.
  137.      */
  138.     if ( (dirp=opendir(".")) == NULL ) {
  139.     errmssg(ERR_WARN,"couldn't open dir '%s'", dir_name);
  140.     return FALSE;
  141.     }
  142.  
  143.     /*
  144.      * Go through each entry in the directory.
  145.      */
  146.     while ( (dp=readdir(dirp)) != NULL ) {
  147.  
  148.     /*
  149.      * Skip the "." and ".." entries.
  150.      */
  151.     if (
  152.         dp->d_name[0] == '.' && (
  153.         dp->d_name[1] == '\0' ||
  154.         ( dp->d_name[1] == '.' && dp->d_name[2] == '\0' )
  155.         )
  156.     ) {
  157.         continue;
  158.     }
  159.  
  160.     /*
  161.      * Create the full pathname to this entry.
  162.      */
  163.     (void) strcpy(ent_basename, dp->d_name);
  164.  
  165.     /*
  166.      * Get the information on this entry.
  167.      */
  168.     if ( stat(ent_basename, &ent_stat) != 0 ) {
  169.         errmssg(ERR_WARN,"couldn't stat '%s'", ent_pathname);
  170.         continue;
  171.     }
  172.  
  173.     /*
  174.      * How we process this entry depends upon what type it is.
  175.      */
  176.     switch ( ent_stat.st_mode & S_IFMT ) {
  177.  
  178.     /*
  179.      * For files, accumulate the disk usage into the directory total.
  180.      */
  181.     case S_IFREG:
  182.  
  183.         /*
  184.          * See if we want to process this file.
  185.          */
  186.         if ( ent_stat.st_nlink > 1 ) {
  187.         if ( Skip_links )
  188.             break;
  189.         if ( Suppress_repeats && fs_linkdone(dir_fsinfop, &ent_stat) )
  190.             break;
  191.         }
  192.  
  193.         nblocks = fs_numblocks(dir_fsinfop, &ent_stat);
  194.         set_usage(&ent_blocks, &ent_stat, nblocks);
  195.         add_usage(dir_blocks_p, &ent_blocks);
  196.         if ( All_entries )
  197.         print_usage(ent_pathname, &ent_blocks);
  198.         break;
  199.  
  200.     /*
  201.      * For directories, we might need to scan recursively.
  202.      */
  203.     case S_IFDIR:
  204.  
  205.         /*
  206.          * Check if we are crossing a mount point.
  207.          */
  208.         if ( !Cross_filesys && dir_statp->st_dev != ent_stat.st_dev )
  209.         break;
  210.  
  211.         /*
  212.          * Get the filesystem information on this diretory.
  213.          */
  214.         ent_fsinfop = fs_getinfo(dir_fsinfop, &ent_stat);
  215.         if ( ent_fsinfop == NULL ) {
  216.         errmssg(ERR_WARN,"couldn't get filesystem info for '%s'",
  217.             ent_pathname);
  218.         break;
  219.         }
  220.  
  221.         /*
  222.          * If we shouldn't descend into this dir, then just get its size.
  223.          */
  224.         if ( !Descend_dirs ) {
  225.         nblocks = fs_numblocks(ent_fsinfop, &ent_stat);
  226.         set_usage(&ent_blocks, &ent_stat, nblocks);
  227.         add_usage(dir_blocks_p, &ent_blocks);
  228.         if ( !Total_only )
  229.             print_usage(ent_pathname, &ent_blocks);
  230.         break;
  231.         }
  232.  
  233.         /*
  234.          * Go get the usage on this directory.
  235.          */
  236.         if ( chdir(ent_basename) != 0 ) {
  237.         errmssg(ERR_WARN,"couldn't chdir to '%s'", ent_pathname);
  238.         break;
  239.         }
  240.         if ( du_dir(ent_pathname, &ent_stat, ent_fsinfop, &ent_blocks) ) {
  241.         if ( Accum_subdirs )
  242.             add_usage(dir_blocks_p, &ent_blocks);
  243.         }
  244.         if ( chdir("..") != 0 ) {
  245.         Print_errors = TRUE;
  246.         errmssg(ERR_WARN,"couldn't chdir back to '%s'", dir_name);
  247.         exit(1);
  248.         }
  249.         break;
  250.  
  251.     /*
  252.      * Special files are ignored.
  253.      */
  254.     default:
  255.         break;
  256.  
  257.     }
  258.  
  259.     }
  260.  
  261.     /*
  262.      * The current directory is complete.
  263.      */
  264.     (void) closedir(dirp);
  265.  
  266.     if ( !Total_only )
  267.     print_usage(dir_name, dir_blocks_p);
  268.     return TRUE;
  269.  
  270. }
  271.  
  272.